Préparez des données pour un organisme de santé publique¶

logo.JPG

L'agence "Santé publique France" a lancé un appel à projets pour rendre les données de santé plus accessibles. L’agence souhaite faire explorer et visualiser des données, pour que ses agents puissent les exploiter.

L'anayse est basée sur le jeu de données Open Food


Sommaire¶

  1. Environnement de développement
    1. Installation de l'environnement
    2. Import des librairies
    3. Fonctions utilitaires
  2. Présentation générale du jeu de données
  3. Nettoyage du jeu de données
  4. Sélection des données à étudier
  5. Analyse des données sélectionnées
    1. Variables qualitatives
      1. Nettoyage des variables qualitatives
      2. Analyse univariée des variables qualitatives
      3. Analyse bivariée avec le nutrition_grade
    2. Variables quantitatives
      1. Nettoyage des variables quantitatives
      2. Analyse univariée des variables quantitatives
      3. Analyse bivariée entre chaque variable quantitative
      4. Analyse des corrélations entre les variables quantitatives
  6. Imputation de données manquantes
  7. Analyse statistique du jeu de données
    1. Analyse après nettoyage et imputation des valeurs manquantes
    2. Analyse en composantes principales (ACP)
    3. ANOVA
  8. Conclusion

Environnement de développement¶

Installation de l'environnement¶

Un environnement virtuel a été créé pour assurer l’isolement du projet et la gestion des dépendances. Les informations de cet environnement (son nom et ses dépendances) sont précisées dans le fichier environment.yml

L'installation de l'environnement virtuel est possible à partir de ce fichier, dans un invite de commande lancer la commande :

conda env create -f environment.yml

Import des librairies¶

Fonctions utilitaires¶

Fonctions utilisées pour automatiser l'analyse des données

Présentation générale du jeu de données¶

Le jeu de données contient : 320772 lignes et 162 colonnes

code url creator created_t created_datetime last_modified_t last_modified_datetime product_name generic_name quantity ... ph_100g fruits-vegetables-nuts_100g collagen-meat-protein-ratio_100g cocoa_100g chlorophyl_100g carbon-footprint_100g nutrition-score-fr_100g nutrition-score-uk_100g glycemic-index_100g water-hardness_100g
0 0000000003087 http://world-fr.openfoodfacts.org/produit/0000... openfoodfacts-contributors 1474103866 2016-09-17T09:17:46Z 1474103893 2016-09-17T09:18:13Z Farine de blé noir NaN 1kg ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1 0000000004530 http://world-fr.openfoodfacts.org/produit/0000... usda-ndb-import 1489069957 2017-03-09T14:32:37Z 1489069957 2017-03-09T14:32:37Z Banana Chips Sweetened (Whole) NaN NaN ... NaN NaN NaN NaN NaN NaN 14.0 14.0 NaN NaN
2 0000000004559 http://world-fr.openfoodfacts.org/produit/0000... usda-ndb-import 1489069957 2017-03-09T14:32:37Z 1489069957 2017-03-09T14:32:37Z Peanuts NaN NaN ... NaN NaN NaN NaN NaN NaN 0.0 0.0 NaN NaN
3 0000000016087 http://world-fr.openfoodfacts.org/produit/0000... usda-ndb-import 1489055731 2017-03-09T10:35:31Z 1489055731 2017-03-09T10:35:31Z Organic Salted Nut Mix NaN NaN ... NaN NaN NaN NaN NaN NaN 12.0 12.0 NaN NaN
4 0000000016094 http://world-fr.openfoodfacts.org/produit/0000... usda-ndb-import 1489055653 2017-03-09T10:34:13Z 1489055653 2017-03-09T10:34:13Z Organic Polenta NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
5 0000000016100 http://world-fr.openfoodfacts.org/produit/0000... usda-ndb-import 1489055651 2017-03-09T10:34:11Z 1489055651 2017-03-09T10:34:11Z Breadshop Honey Gone Nuts Granola NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
6 0000000016117 http://world-fr.openfoodfacts.org/produit/0000... usda-ndb-import 1489055730 2017-03-09T10:35:30Z 1489055730 2017-03-09T10:35:30Z Organic Long Grain White Rice NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
7 0000000016124 http://world-fr.openfoodfacts.org/produit/0000... usda-ndb-import 1489055711 2017-03-09T10:35:11Z 1489055712 2017-03-09T10:35:12Z Organic Muesli NaN NaN ... NaN NaN NaN NaN NaN NaN 7.0 7.0 NaN NaN
8 0000000016193 http://world-fr.openfoodfacts.org/produit/0000... usda-ndb-import 1489055651 2017-03-09T10:34:11Z 1489055651 2017-03-09T10:34:11Z Organic Dark Chocolate Minis NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
9 0000000016513 http://world-fr.openfoodfacts.org/produit/0000... usda-ndb-import 1489055654 2017-03-09T10:34:14Z 1489055654 2017-03-09T10:34:14Z Organic Sunflower Oil NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN

10 rows × 162 columns

Affichage du nombre de valeurs manquantes en % pour chaque colonne
Valeurs manquantes en %
last_modified_t 0.000000
last_modified_datetime 0.000000
creator 0.000623
created_t 0.000935
created_datetime 0.002806
... ...
ingredients_that_may_be_from_palm_oil 100.000000
ingredients_from_palm_oil 100.000000
no_nutriments 100.000000
nervonic-acid_100g 100.000000
water-hardness_100g 100.000000

162 rows × 1 columns

Affichage graphique du remplissage des colonnes
<AxesSubplot:>

Il y'a beaucoup de colonnes vides ou très peu remplies (plus de 75% de valeurs manquantes).

Nettoyage du jeu de données¶

Avant de commencer l'analyse, il faut procéder à un nettoyage du jeu de données pour qu'il soit plus complet et plus uniforme.

On commence par supprimer les colonnes peu remplies, c'est à dire celles qui ont plus de 75% de valeurs manquantes

On supprime ensuite les lignes dont aucune donnée nutritionnelle n'a été renseignée (les colonnes terminant par _100g)

On supprime les lignes dont le code ou le nom du produit n'est pas renseigné

On vérifie si il y a des doublons pour le code des produits

code url creator created_t created_datetime last_modified_t last_modified_datetime product_name quantity brands ... fiber_100g proteins_100g salt_100g sodium_100g vitamin-a_100g vitamin-c_100g calcium_100g iron_100g nutrition-score-fr_100g nutrition-score-uk_100g

0 rows × 50 columns

Il n'y pas de doublon à déclarer.

On affiche donc les informations du data après le nettoyage :

Nombre de lignes supprimées : 61338
Nombre de colonnes supprimées : 112
Colonnes supprimées : ['generic_name', 'packaging', 'packaging_tags', 'origins', 'origins_tags', 'manufacturing_places', 'manufacturing_places_tags', 'labels', 'labels_tags', 'labels_fr', 'emb_codes', 'emb_codes_tags', 'first_packaging_code_geo', 'cities', 'cities_tags', 'purchase_places', 'stores', 'allergens', 'allergens_fr', 'traces', 'traces_tags', 'traces_fr', 'no_nutriments', 'ingredients_from_palm_oil', 'ingredients_from_palm_oil_tags', 'ingredients_that_may_be_from_palm_oil', 'ingredients_that_may_be_from_palm_oil_tags', 'nutrition_grade_uk', 'image_url', 'image_small_url', 'energy-from-fat_100g', 'butyric-acid_100g', 'caproic-acid_100g', 'caprylic-acid_100g', 'capric-acid_100g', 'lauric-acid_100g', 'myristic-acid_100g', 'palmitic-acid_100g', 'stearic-acid_100g', 'arachidic-acid_100g', 'behenic-acid_100g', 'lignoceric-acid_100g', 'cerotic-acid_100g', 'montanic-acid_100g', 'melissic-acid_100g', 'monounsaturated-fat_100g', 'polyunsaturated-fat_100g', 'omega-3-fat_100g', 'alpha-linolenic-acid_100g', 'eicosapentaenoic-acid_100g', 'docosahexaenoic-acid_100g', 'omega-6-fat_100g', 'linoleic-acid_100g', 'arachidonic-acid_100g', 'gamma-linolenic-acid_100g', 'dihomo-gamma-linolenic-acid_100g', 'omega-9-fat_100g', 'oleic-acid_100g', 'elaidic-acid_100g', 'gondoic-acid_100g', 'mead-acid_100g', 'erucic-acid_100g', 'nervonic-acid_100g', 'sucrose_100g', 'glucose_100g', 'fructose_100g', 'lactose_100g', 'maltose_100g', 'maltodextrins_100g', 'starch_100g', 'polyols_100g', 'casein_100g', 'serum-proteins_100g', 'nucleotides_100g', 'alcohol_100g', 'beta-carotene_100g', 'vitamin-d_100g', 'vitamin-e_100g', 'vitamin-k_100g', 'vitamin-b1_100g', 'vitamin-b2_100g', 'vitamin-pp_100g', 'vitamin-b6_100g', 'vitamin-b9_100g', 'folates_100g', 'vitamin-b12_100g', 'biotin_100g', 'pantothenic-acid_100g', 'silica_100g', 'bicarbonate_100g', 'potassium_100g', 'chloride_100g', 'phosphorus_100g', 'magnesium_100g', 'zinc_100g', 'copper_100g', 'manganese_100g', 'fluoride_100g', 'selenium_100g', 'chromium_100g', 'molybdenum_100g', 'iodine_100g', 'caffeine_100g', 'taurine_100g', 'ph_100g', 'fruits-vegetables-nuts_100g', 'collagen-meat-protein-ratio_100g', 'cocoa_100g', 'chlorophyl_100g', 'carbon-footprint_100g', 'glycemic-index_100g', 'water-hardness_100g']

Le jeu de données contient : 259434 lignes et 50 colonnes

Affichage graphique du remplissage des colonnes après le nettoyage
<AxesSubplot:>
code url creator created_t created_datetime last_modified_t last_modified_datetime product_name quantity brands ... fiber_100g proteins_100g salt_100g sodium_100g vitamin-a_100g vitamin-c_100g calcium_100g iron_100g nutrition-score-fr_100g nutrition-score-uk_100g
1 0000000004530 http://world-fr.openfoodfacts.org/produit/0000... usda-ndb-import 1489069957 2017-03-09T14:32:37Z 1489069957 2017-03-09T14:32:37Z Banana Chips Sweetened (Whole) NaN NaN ... 3.6 3.57 0.00000 0.000 0.000000 0.0214 0.000 0.00129 14.0 14.0
2 0000000004559 http://world-fr.openfoodfacts.org/produit/0000... usda-ndb-import 1489069957 2017-03-09T14:32:37Z 1489069957 2017-03-09T14:32:37Z Peanuts NaN Torn & Glasser ... 7.1 17.86 0.63500 0.250 0.000000 0.0000 0.071 0.00129 0.0 0.0
3 0000000016087 http://world-fr.openfoodfacts.org/produit/0000... usda-ndb-import 1489055731 2017-03-09T10:35:31Z 1489055731 2017-03-09T10:35:31Z Organic Salted Nut Mix NaN Grizzlies ... 7.1 17.86 1.22428 0.482 NaN NaN 0.143 0.00514 12.0 12.0
4 0000000016094 http://world-fr.openfoodfacts.org/produit/0000... usda-ndb-import 1489055653 2017-03-09T10:34:13Z 1489055653 2017-03-09T10:34:13Z Organic Polenta NaN Bob's Red Mill ... 5.7 8.57 NaN NaN NaN NaN NaN NaN NaN NaN
5 0000000016100 http://world-fr.openfoodfacts.org/produit/0000... usda-ndb-import 1489055651 2017-03-09T10:34:11Z 1489055651 2017-03-09T10:34:11Z Breadshop Honey Gone Nuts Granola NaN Unfi ... 7.7 13.46 NaN NaN NaN NaN 0.038 0.00346 NaN NaN
6 0000000016117 http://world-fr.openfoodfacts.org/produit/0000... usda-ndb-import 1489055730 2017-03-09T10:35:30Z 1489055730 2017-03-09T10:35:30Z Organic Long Grain White Rice NaN Lundberg ... NaN 8.89 NaN NaN NaN 0.0027 0.044 NaN NaN NaN
7 0000000016124 http://world-fr.openfoodfacts.org/produit/0000... usda-ndb-import 1489055711 2017-03-09T10:35:11Z 1489055712 2017-03-09T10:35:12Z Organic Muesli NaN Daddy's Muesli ... 9.4 14.06 0.13970 0.055 NaN NaN 0.062 0.00422 7.0 7.0
8 0000000016193 http://world-fr.openfoodfacts.org/produit/0000... usda-ndb-import 1489055651 2017-03-09T10:34:11Z 1489055651 2017-03-09T10:34:11Z Organic Dark Chocolate Minis NaN Equal Exchange ... 7.5 5.00 NaN NaN NaN NaN 0.050 0.01125 NaN NaN
9 0000000016513 http://world-fr.openfoodfacts.org/produit/0000... usda-ndb-import 1489055654 2017-03-09T10:34:14Z 1489055654 2017-03-09T10:34:14Z Organic Sunflower Oil NaN Napa Valley Naturals ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
10 0000000016612 http://world-fr.openfoodfacts.org/produit/0000... usda-ndb-import 1489055731 2017-03-09T10:35:31Z 1489055731 2017-03-09T10:35:31Z Organic Adzuki Beans NaN Unfi ... 12.5 22.92 NaN NaN NaN NaN 0.062 0.00450 NaN NaN
11 0000000016650 http://world-fr.openfoodfacts.org/produit/0000... usda-ndb-import 1489055668 2017-03-09T10:34:28Z 1489055668 2017-03-09T10:34:28Z Organic Penne Pasta NaN Gardentime ... 1.8 14.04 NaN NaN NaN 0.0042 NaN 0.00126 NaN NaN
12 0000000016872 http://world-fr.openfoodfacts.org/produit/0000... usda-ndb-import 1489055650 2017-03-09T10:34:10Z 1489055651 2017-03-09T10:34:11Z Zen Party Mix NaN Sunridge ... 6.7 16.67 1.60782 0.633 NaN NaN 0.133 0.00360 12.0 12.0
13 0000000016933 http://world-fr.openfoodfacts.org/produit/0000... usda-ndb-import 1489055651 2017-03-09T10:34:11Z 1489055651 2017-03-09T10:34:11Z Organic Golden Flax Seeds NaN Unfi ... 38.1 19.05 0.09652 0.038 NaN NaN 0.286 0.01286 NaN NaN
14 0000000017497 http://world-fr.openfoodfacts.org/produit/0000... usda-ndb-import 1489055678 2017-03-09T10:34:38Z 1489055678 2017-03-09T10:34:38Z Organic Spicy Punks NaN Eden ... 15.2 30.30 0.57658 0.227 NaN NaN NaN 0.00545 NaN NaN
15 0000000018012 http://world-fr.openfoodfacts.org/produit/0000... usda-ndb-import 1489055652 2017-03-09T10:34:12Z 1489055653 2017-03-09T10:34:13Z Cinnamon Nut Granola NaN Grizzlies ... 9.1 14.55 0.02286 0.009 0.000273 NaN NaN 0.00131 0.0 0.0
16 0000000018050 http://world-fr.openfoodfacts.org/produit/0000... usda-ndb-import 1489050462 2017-03-09T09:07:42Z 1489050462 2017-03-09T09:07:42Z Organic Hazelnuts NaN Grizzlies ... 10.7 14.29 0.01016 0.004 NaN 0.0064 0.107 0.00450 0.0 0.0
17 0000000018173 http://world-fr.openfoodfacts.org/produit/0000... usda-ndb-import 1489055667 2017-03-09T10:34:27Z 1489055667 2017-03-09T10:34:27Z Organic Sweetened Banana Chips NaN Unfi ... 3.3 3.33 NaN NaN NaN NaN NaN 0.00120 NaN NaN
18 0000000018197 http://world-fr.openfoodfacts.org/produit/0000... usda-ndb-import 1489055652 2017-03-09T10:34:12Z 1489055652 2017-03-09T10:34:12Z Lotus Organic Brown Jasmine Rice NaN Unfi ... 2.2 8.89 NaN NaN NaN NaN NaN NaN NaN NaN
19 0000000018227 http://world-fr.openfoodfacts.org/produit/0000... usda-ndb-import 1489055682 2017-03-09T10:34:42Z 1489055682 2017-03-09T10:34:42Z Organic Oat Groats NaN Pcc ... 9.5 16.67 0.02540 0.010 NaN NaN 0.048 0.00429 -6.0 -6.0
20 0000000018265 http://world-fr.openfoodfacts.org/produit/0000... usda-ndb-import 1489055706 2017-03-09T10:35:06Z 1489055706 2017-03-09T10:35:06Z Energy Power Mix NaN Sunridge ... 5.0 7.50 0.28448 0.112 0.000075 0.0225 0.100 0.00180 14.0 14.0

20 rows × 50 columns

Le jeu de données contient : 259434 lignes et 50 colonnes

Sélection des données à étudier¶

Dans cette partie on va sélectionner les données intéressantes pour notre étude

On commence par catégoriser nos variables en 2 groupes : les variables qualitatives et quantitatives

Variables quantitatives: 
['additives_n', 'ingredients_from_palm_oil_n', 'ingredients_that_may_be_from_palm_oil_n', 'energy_100g', 'fat_100g', 'saturated-fat_100g', 'trans-fat_100g', 'cholesterol_100g', 'carbohydrates_100g', 'sugars_100g', 'fiber_100g', 'proteins_100g', 'salt_100g', 'sodium_100g', 'vitamin-a_100g', 'vitamin-c_100g', 'calcium_100g', 'iron_100g', 'nutrition-score-fr_100g', 'nutrition-score-uk_100g']

Variables qualitatives: 
['code', 'url', 'creator', 'created_t', 'created_datetime', 'last_modified_t', 'last_modified_datetime', 'product_name', 'quantity', 'brands', 'brands_tags', 'categories', 'categories_tags', 'categories_fr', 'countries', 'countries_tags', 'countries_fr', 'ingredients_text', 'serving_size', 'additives', 'additives_tags', 'additives_fr', 'nutrition_grade_fr', 'pnns_groups_1', 'pnns_groups_2', 'states', 'states_tags', 'states_fr', 'main_category', 'main_category_fr']

À partir de cette catégorisation, on ne va garder que les colonnes pertinentes dans le cas de notre étude :

Pour les variables qualitatives on sélectionne :

  • product_name
  • nutrition_grade_fr
  • pnns_groups_1
  • pnns_groups_2
  • main_category

Pour les variables quantitatives on sélectionne :

  • energy_100g
  • fat_100g
  • saturated-fat_100g
  • trans-fat_100g
  • cholesterol_100g
  • carbohydrates_100g
  • sugars_100g
  • fiber_100g
  • proteins_100g
  • salt_100g
  • sodium_100g
  • vitamin-a_100g
  • vitamin-c_100g
  • calcium_100g
  • iron_100g
  • nutrition-score-fr_100g
Nombre de lignes supprimées : 0
Nombre de colonnes supprimées : 29
Colonnes supprimées : ['code', 'url', 'creator', 'created_t', 'created_datetime', 'last_modified_t', 'last_modified_datetime', 'quantity', 'brands', 'brands_tags', 'categories', 'categories_tags', 'categories_fr', 'countries', 'countries_tags', 'countries_fr', 'ingredients_text', 'serving_size', 'additives_n', 'additives', 'additives_tags', 'additives_fr', 'ingredients_from_palm_oil_n', 'ingredients_that_may_be_from_palm_oil_n', 'states', 'states_tags', 'states_fr', 'main_category_fr', 'nutrition-score-uk_100g']

Le jeu de données contient : 259434 lignes et 21 colonnes

Analyse des données sélectionnées¶

On va maintenant analyser notre jeu de données sélectionné en s'intéressant principalement au nutrition_grade des produtis, ainsi qu'à leurs valeurs nuutritionnelles.

Variables qualitatives¶

On commence par analyser les données qualitatives

Nettoyage des variables qualitatives¶

On effectue un second nettoyage un peu plus poussé sur les données qualitatives, afin d'uniformiser les données :

  • On passe les valeurs en minuscule
  • On remplace les valeurs à "unknown" par la valeur Nan
product_name nutrition_grade_fr pnns_groups_1 pnns_groups_2 main_category
1 banana chips sweetened (whole) d NaN NaN NaN
2 peanuts b NaN NaN NaN
3 organic salted nut mix d NaN NaN NaN
4 organic polenta NaN NaN NaN NaN
5 breadshop honey gone nuts granola NaN NaN NaN NaN

Analyse univariée des variables qualitatives¶

product_name          183134
nutrition_grade_fr         5
pnns_groups_1             13
pnns_groups_2             36
main_category           2355
dtype: int64

On affiche les graphiques pour les colonnes ne présentant pas trop de valeurs uniques. On regroupe les valeurs représentant moins de 1.5% des données dans une catégorie nommée 'other'

Graphiques pour les données qualitatives

On voit que la répartition du nutri-score (noté de A à E) n'est pas uniforme, il y a une majorité de produits avec un mauvais nutriscore (C, D et E).

Les 19 catégories les plus courantes représentent environ 50% des produits.

Pour les différents groupes d'aliments (groupes 1 et 2), il y a une majorité de produits sucrés, laitiers ou céréales.

Analyse bivariée avec le nutrition_grade¶

Ici on va afficher la répartition du nutrition_grade en fonction des autres variables qualitatives

sugary snacksmilk and dairy productscereals and potatoesbeveragescomposite foodsfish meat eggsfat and saucesfruits and vegetablessalty snacks02k4k6k8k10k
nutrition_grade_frabcdeRépartion des pnns_groups_1 par nutrition_grade_frtop_pnns_groups_1count
plotly-logomark
one-dish mealsbiscuits and cakescerealssweetscheesemilk and yogurtdressings and sauceschocolate productsvegetablesprocessed meatnon-sugared beveragesfish and seafoodsweetened beveragesappetizersfruit juicesbreadfatsbreakfast cerealsfruitsmeat050010001500200025003000350040004500
nutrition_grade_frabcdeRépartion des pnns_groups_2 par nutrition_grade_frtop_pnns_groups_2count
plotly-logomark
en:groceriesen:beveragesen:chocolatesen:plant-based-foods-and-beveragesen:canned-foodsen:biscuitsen:mealsen:frozen-foodsen:breakfastsen:sugary-snacksen:dessertsen:breadsen:cheesesen:pastasen:meals-with-meaten:chips-and-friesen:cakesen:salted-spreads0500100015002000
nutrition_grade_frabcdeRépartion des main_category par nutrition_grade_frtop_main_categorycount
plotly-logomark

On peut voir par exemple que les chocolats, biscuits, cakes, sugary snack ... ont généralement un mauvais nutri-score (D ou E), et que les canettes de nourriture, laits, céréales, fruits ... ont un bon nutri-score (A ou B)

Variables quantitatives¶

On analyse maintenant les données quantitatives

Nettoyage des variables quantitatives¶

On effectue un second nettoyage un peu plus poussé sur les données quantitatives, afin d'uniformiser les données :

  • On supprime les valeurs inférieures à 0 et supérieures à 100 pour les données nutritionnelles
  • On supprime les outliers par la méthode de l'inter-quartile pour les autres données
  • On supprime les produits dont la somme en g des données nutritionnelles est supérieure à 100
  • On supprime les produits dont l'énergie calculée est trop différente de l'énergie renseignée
energy_100g fat_100g saturated-fat_100g trans-fat_100g cholesterol_100g carbohydrates_100g sugars_100g fiber_100g proteins_100g salt_100g sodium_100g vitamin-a_100g vitamin-c_100g calcium_100g iron_100g nutrition-score-fr_100g
count 2.577730e+05 240584.000000 226641.000000 143159.000000 143950.000000 240276.000000 241910.000000 198587.000000 256605.000000 252527.000000 252488.000000 137398.000000 140655.00000 140837.000000 140305.000000 218463.000000
mean 1.140497e+03 12.701388 5.115709 0.073428 0.020079 32.091647 15.993129 2.863581 7.074330 2.037957 0.802467 0.000397 0.02335 0.125119 0.003654 9.151724
std 6.484434e+03 17.574028 8.008095 1.540612 0.358234 29.765368 22.345150 12.933636 8.418758 129.023620 50.800621 0.073320 2.23813 3.320757 0.214528 9.052588
min 0.000000e+00 0.000000 0.000000 -3.570000 0.000000 0.000000 -17.860000 -6.700000 -800.000000 0.000000 0.000000 -0.000340 -0.00210 0.000000 -0.000260 -15.000000
25% 3.730000e+02 0.000000 0.000000 0.000000 0.000000 6.000000 1.300000 0.000000 0.700000 0.063500 0.025000 0.000000 0.00000 0.000000 0.000000 1.000000
50% 1.100000e+03 5.000000 1.790000 0.000000 0.000000 20.600000 5.710000 1.500000 4.760000 0.584200 0.230000 0.000000 0.00000 0.035000 0.001010 10.000000
75% 1.674000e+03 20.000000 7.140000 0.000000 0.020000 58.500000 24.000000 3.600000 10.000000 1.379220 0.543000 0.000107 0.00370 0.106000 0.002400 16.000000
max 3.251373e+06 714.290000 550.000000 369.000000 95.238000 2916.670000 3520.000000 5380.000000 430.000000 64312.800000 25320.000000 26.700000 716.98110 694.737000 50.000000 40.000000

On voit que pour les données nutritionnelles (colonnes terminant par _100g) il y a des incohérences, il y a des valeurs négatives et des valeurs supérieures à 100 ce qui est impossible. Pour l'énergie et le nutrition-score exprimé en valeur numérique il y a également des abérrations, ici on utilisera la méthode de l'inter-quartile

On va donc supprimer les valeurs en dessous de 0 et au dessous de 100 pour les colonnes suivantes :

  • fat_100g
  • saturated-fat_100g
  • trans-fat_100g
  • cholesterol_100g
  • carbohydrates_100g
  • sugars_100g
  • fiber_100g
  • proteins_100g
  • salt_100g
  • sodium_100g
  • vitamin-a_100g
  • vitamin-c_100g
  • calcium_100g
  • iron_100g

On va supprimer les outliers par la méthode de l'écart inter-quartiles, pour les colonnes suivantes :

  • energy_100g
  • nutrition-score-fr_100g
energy_100g fat_100g saturated-fat_100g trans-fat_100g cholesterol_100g carbohydrates_100g sugars_100g fiber_100g proteins_100g salt_100g sodium_100g vitamin-a_100g vitamin-c_100g calcium_100g iron_100g nutrition-score-fr_100g
count 256709.000000 240580.000000 226638.000000 143150.000000 143950.000000 240258.00000 241892.000000 198582.000000 256601.000000 252371.000000 252454.000000 137397.000000 140651.000000 140827.000000 140304.000000 218459.000000
mean 1113.395627 12.696195 5.111649 0.067118 0.020079 32.07302 15.975216 2.833600 7.077845 1.593437 0.649009 0.000397 0.014532 0.101944 0.003654 9.151159
std 781.536587 17.497914 7.906154 0.944894 0.358234 29.16708 21.169760 4.591686 8.163246 6.261328 2.663027 0.073320 0.461745 0.585645 0.214529 9.051708
min 0.000000 0.000000 0.000000 0.000000 0.000000 0.00000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -15.000000
25% 372.000000 0.000000 0.000000 0.000000 0.000000 6.00000 1.300000 0.000000 0.700000 0.063500 0.025000 0.000000 0.000000 0.000000 0.000000 1.000000
50% 1093.000000 5.000000 1.790000 0.000000 0.000000 20.59000 5.710000 1.500000 4.760000 0.584200 0.230000 0.000000 0.000000 0.035000 0.001010 10.000000
75% 1674.000000 20.000000 7.140000 0.000000 0.020000 58.45750 24.000000 3.600000 10.000000 1.374140 0.543000 0.000107 0.003700 0.106000 0.002400 16.000000
max 3619.000000 100.000000 100.000000 100.000000 95.238000 100.00000 100.000000 100.000000 100.000000 100.000000 100.000000 26.700000 100.000000 99.006000 50.000000 38.000000

Nos données quantitatives sont maintenant plus uniformes. Analysons comment les étudier :

Les données nutritionnelles principales sont :

  • fat_100g (lipides), décliné ensuite par les données :
    • saturated-fat_100g
    • trans-fat_100g
    • cholesterol_100g
  • carbohydrates_100g (glucides), décliné ensuite par les données :
    • sugars_100g
    • fiber_100g
  • proteins_100g (protéines)
  • salt_100g, décliné ensuite par :
    • sodium_100g

Ces données principales servent à calculer :

  • energy_100g

Le calcul des calories d'un aliment s'effectue selon un processus normalisé au niveau européen et baptisé système « 4/4/9 » Ce système implique que l'équivalent calorique d'un gramme de protéines, de glucides et de lipides - nos trois principaux « carburants » nutritionnels - correspond respectivement à 4, 4 et 9 kcal.

1 gr de proteine apporte 4 kcal 1 gr de glucide (carbohydrate) apporte 4 kcal 1 gr de lipide apporte 9 kcal

On va rajouter 3 colonnes dans notre data :

  • sum_nutritional_elements_100g : c'est la somme en g des données nutritionnelles principales (on ajoute le sel ici)
  • energy_calculated_100g : c'est l'énergie calculée à partir des données nutritionnelles principales (on ne tient pas compte du sel)
  • energy_difference : c'est la différence d'énergie entre celle calculée et celle renseignée
sum_nutritional_elements_100g energy_calculated_100g energy_difference
count 233195.000000 238411.000000 237191.000000
mean 53.390081 1130.291358 59.553247
std 33.897665 812.105339 146.763682
min 0.000000 0.000000 0.000000
25% 20.636140 363.054770 7.644560
50% 51.942180 1108.424510 22.745000
75% 88.203350 1674.800000 57.127860
max 239.690000 6001.478320 4187.125610

Commencons par supprimer les produits dont la somme en g des valeurs nutritionnelles principales est supérieure à 100, car c'est impossible. Cela signifie que les données sont mal renseignées pour ce produit.

Affichons maintenant le graphique représentant pour les produits la différence entre l'énergie renseignée et celle calculée

On voit que pour la majorité des produits la différence d'énergie est très faible, ce qui signifie que notre calcul en utilisant les données nutritionnelles principales et le système 4/4/9 représente assez bien nos données. On choisit ici de supprimer les produits qui ont une différence supérieure à 300 kJ (correspondant à 72 kcal), cela signifie qu'il manque des données nutritionnelles ou qu'elles sont mal renseignées. Ceci nous permettra d'avoir des données plus pertinentes pour l'analyse

energy_100g fat_100g saturated-fat_100g trans-fat_100g cholesterol_100g carbohydrates_100g sugars_100g fiber_100g proteins_100g salt_100g sodium_100g vitamin-a_100g vitamin-c_100g calcium_100g iron_100g nutrition-score-fr_100g
count 222245.000000 222245.000000 198023.000000 135098.000000 135715.000000 222245.000000 212184.000000 171290.000000 222245.000000 222245.000000 222222.000000 129925.000000 132881.000000 132880.000000 132530.000000 192466.000000
mean 1094.718453 12.198456 4.859993 0.063144 0.020091 31.262919 15.713362 2.713325 6.957271 1.543991 0.607933 0.000363 0.011288 0.101180 0.003540 8.996976
std 776.236035 16.626035 7.244601 0.917228 0.327477 28.658474 20.713074 3.872652 7.875833 6.134678 2.415342 0.074111 0.299065 0.594034 0.214334 9.018269
min 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 -14.000000
25% 360.000000 0.000000 0.000000 0.000000 0.000000 5.930000 1.500000 0.000000 0.700000 0.066040 0.026000 0.000000 0.000000 0.000000 0.000000 1.000000
50% 1069.000000 4.900000 1.790000 0.000000 0.000000 20.000000 5.830000 1.600000 4.650000 0.600000 0.236220 0.000000 0.000000 0.035000 0.000960 9.000000
75% 1644.000000 19.720000 7.140000 0.000000 0.022000 57.140000 23.500000 3.600000 10.000000 1.384300 0.545000 0.000107 0.003800 0.105000 0.002400 16.000000
max 3615.000000 100.000000 100.000000 100.000000 95.238000 100.000000 100.000000 100.000000 100.000000 100.000000 39.370079 26.700000 57.140000 99.006000 50.000000 37.000000
Affichage des informations sur le nouveau jeu de données
Nombre de lignes supprimées : 37189
Nombre de colonnes supprimées : 0
Colonnes supprimées : []

Le jeu de données contient : 222245 lignes et 22 colonnes

Analyse univariée des variables quantitatives¶

On affiche les boîtes à moustaches ainsi que les histogrammes pour chaque variable quantitative

Si l'on se fie aux boîtes à moustaches on voit qu'il reste des outliers. Cela est du à la trop grandes répartition des valeurs autour de 0 pour certaines variables. Durant le nettoyage on a décidé de supprimer les valeurs en dessous de 0 et au dessus de 100 pour les données nutritionnelles, et de compléter le nettoyage en vérifiant le calcul de la somme des données nutritionnelles et le calcul de l'énergie.

La détermination des outliers avec la méthode de l'écart-interquartile n'est donc ici pas très pertinente, excepté pour l'énergie et le nutri-score mais les outliers ont été correctement supprimés lors du nettoyage.

On voit que les variables qui ont une distribution plus étalée correspondent à nos trois principaux « carburants » nutritionnels, protéine, glucide et le gras, ainsi que l'énergie et le nutriscore. Les autres variables étant des déclinaisons des principaux carburants sont moins souvent présente, d'ou leur plus grande répartion autour des petites valeurs.

Pour la suite de l'étude on va réduire les valeurs quantitatives sélectionnées. On ne va pas garder celles qui ont beaucoup trop de valeurs autour de 0. On ne va étudier que les variables ayant une répartion des valeurs assez importante pour pouvoir les comparer avec la variation d'énergie et le nutriscore.

Variables quantitatives sélectionnnées :

  • energy_100g
  • fat_100g
  • saturated-fat_100g
  • carbohydrates_100g
  • sugars_100g
  • fiber_100g
  • proteins_100g
  • salt_100g
  • sodium_100g
  • nutrition-score-fr_100g
<class 'pandas.core.frame.DataFrame'>
Int64Index: 222245 entries, 1 to 320768
Data columns (total 15 columns):
 #   Column                   Non-Null Count   Dtype  
---  ------                   --------------   -----  
 0   product_name             222245 non-null  object 
 1   nutrition_grade_fr       192467 non-null  object 
 2   pnns_groups_1            47646 non-null   object 
 3   pnns_groups_2            47729 non-null   object 
 4   main_category            54524 non-null   object 
 5   energy_100g              222245 non-null  float64
 6   fat_100g                 222245 non-null  float64
 7   saturated-fat_100g       198023 non-null  float64
 8   carbohydrates_100g       222245 non-null  float64
 9   sugars_100g              212184 non-null  float64
 10  fiber_100g               171290 non-null  float64
 11  proteins_100g            222245 non-null  float64
 12  salt_100g                222245 non-null  float64
 13  sodium_100g              222222 non-null  float64
 14  nutrition-score-fr_100g  192466 non-null  float64
dtypes: float64(10), object(5)
memory usage: 27.1+ MB

Analyse bivariée entre chaque variable quantitative¶

Analysons maintenant les relations entre chaque variable quantitative

On remarque :

  • Une corrélation entre les principaux carburants et leurs déclinaisons (fat avec saturated_fat, et carbohydrates avec sugars)
  • une corrélation parfaite entre salt_100g et sodium_100g (ce qui est logique car le sodium est un composé du sel)
  • L'énergie est le plus corrélé avec le gras, puis ensuite avec les glucides.
  • Le nutri_score est beaucoup impacté par l'énergie (et donc le gras car ils sont corrélés)

Analyse des corrélations entre les variables quantitatives¶

Regardons maintenant la matrice de corrélations

<AxesSubplot:>

Les indices de corrélation entre chaque variable quantitative nous permettent d'affirmer les remarques faites précedemment, à savoir :

  • Une corrélation entre les principaux carburants et leurs déclinaisons (fat avec saturated_fat, et carbohydrates avec sugars)
  • une corrélation parfaite entre salt_100g et sodium_100g (ce qui est logique car le sodium est un composé du sel)
  • L’énergie est le plus corrélé avec le gras, puis ensuite avec les glucides.
  • Le nutri_score est beaucoup impacté par l’énergie (et donc le gras car ils sont corrélés)

Imputation de données manquantes¶

Afon d'avoir un jeu de données plus complet pour pousser notre analyse, on va maintenant imputer les valeurs des données manquantes pour nos colonnes possédant encore un % de valeurs à Nan

Valeurs manquantes en %
product_name 0.000000
energy_100g 0.000000
fat_100g 0.000000
carbohydrates_100g 0.000000
proteins_100g 0.000000
salt_100g 0.000000
sodium_100g 0.010349
sugars_100g 4.526986
saturated-fat_100g 10.898783
nutrition_grade_fr 13.398727
nutrition-score-fr_100g 13.399177
fiber_100g 22.927400
main_category 75.466715
pnns_groups_2 78.524151
pnns_groups_1 78.561497
<AxesSubplot:>

On voit que les colonnes suivantes ne sont pas encore complètes :

  • nutrition_grade_fr
  • nutrition-score-fr_100g
  • saturated-fat_100g
  • sugars_100g
  • fiber_100g

(On n'imputera pas les valeurs manquantes pour les variables qualitatives)

On va commencer par imputer les valeurs sur les données nutritionnelles par la médiane (et non par la moyenne car il y'a beaucoup d'outliers pour ces colonnes comme on a pu le voir avec les boîtes à moustaches)

Imputation des valeurs manquantes par la médiane pour les colonne suivantes : 'saturated-fat_100g', 'sugars_100g', 'fiber_100g'
<AxesSubplot:>

Maintenant que toutes les données nutritionelles sont complètes, on va imputer les valeurs manquantes de la colonne 'nutrition_grade_fr' (valeurs notées de A à E), en utilisant l'algorithme knn (Méthode des k plus proches voisins), ce qui permet d'imputer les valeurs d'un produit selon les produits qui lui ressemble le plus.

Cette colonne une fois complète nous permettra de déterminer les valeurs manquantes de la colonne 'nutrition-score-fr_100g', ces 2 colonnes étant étroitement corrélées. Pour ce faire, connaissant le nutrition-grade d'un produit, si son nutrition-score est manquant, on l'imputera avec la moyenne des nutrition-score dont le nutrition-grade est le même.

<AxesSubplot:>

Nos données quantitatives sont maintenant complètes, on va pouvoir aller un peu plus loin dans l'analyse des variables quantitatives.

Analyse statistique du jeu de données¶

On commencera par une analyse générale de notre jeu de données, pour voir si les remarques faites précedemment sont toujours valables après l'imputation des données manquantes, on vérifie que notre jeu de données à toujours "la même tendance". On fera ensuite une analyse descriptive du jeu de données.

Analyse après nettoyage et imputation des valeurs manquantes¶

<AxesSubplot:>

D'après l'analyse bivariée entre chaque variable quantitative et la matrice de corrélation, on remarque très peu de changement par rapport à la présente analyse faite avant l'imputation des données manquantes. L'imputation des données manquantes n'a donc pas modifié la tendance de notre de jeu de données, mais il est maintenant complet et permet une analyse plus poussée.

Analyse en Composantes Principales (ACP)¶

On va ici étudier la variabilité entre les individus, ainsi que les liaisons entre les variables.

Le nombre de composantes à analyser est de 4

l'ACP nous a permis de déterminer 4 composantes principales (F1 à F4), qui représentent les axes principaux d'inertie et totalisent à eux 86.4% de l'inertie du nuage de points des individus. Les axes d'inertie suivant sont trop peu représentatifs pour être intéressants à étudier.

La composante F1 est corrélée avec l'énergie, le nutrition_grade, le gras et le gras saturé. Si l'on se déplace sur la composante F1, on observe donc une augmentation de nutrition_grade en passant de A vers E, l'énergie du produit sera également plus importante. Comme vu précédemment, c'est bien le gras qui impacte le plus l'énergie du produit et son nutrition_grade. Les autres nutriments l'impactent aussi mais plus faiblement.

La composante F2 est corrélée avec le sel et le sodium. Si l'on se déplace sur la composante F2, les produits sont de plus en plus salés, et correspondent à un nutrition_grade de rang C ou D. Ils sont également de moins en moins gras et caloriques.

La composante F3 est corrélée positivement avec les glucides et le sucre, et négativement avec la protéine. Si l'on se déplace vers la droite sur la composante F3, les produits seront composés de plus de glucides et de moins de protéines sans impacter grandement l'énergie.

La composante F4 est corrélée à la fibre et aux protéines. Si l'on se déplace sur la composante F4, les produits seront composés de plus de fibres et de protéines, et le nutrition_grade sera impacté dans le sens inverse, les produits auront donc un meilleur rang, allant de E vers A.

Voici les hypothèses que l'on peut faire en fonction des différents rangs :

  • A : produits avec peu de gras / sucres, et plus de protéines et de fibres
  • B : produits avec un peu de tout mais en faible quantité
  • C : produits avec un peu de tout en faible quantité mais plus salé
  • D : produits majoritairement gras / sucrés
  • E : produits majoritairement très gras / sucrés

ANOVA¶

Étudions maintenant l'analyse de la variance entre chaque variable quantitative et le nutrition_grade

ANOVA entre chaque variable quantitative et la variable nutrition_grade

Avec ces boîtes à moustaches on observe la répartition des classes du nutrition_grade (A à E), pour chaque variable quantitative. On calcule ensuite le rapport de corrélation des variables (compris entre 0 et 1), qui est le rapport entre les variances interclasses et la variance totale. Il n'y a pas corrélation si les moyennes pas classes sont toutes égales ou presque. Il y a corrélation si les moyennes par classes sont très différentes.

On observe donc ici que les variables les plus corrélées avec le nutrition_grade sont :

  • energy_100g (R = 0.4078)
  • fat_100g (R=0.3101)
  • saturated_fat_100g (0.4291)

Les glucides et le sucres le sont beaucoup moins :

  • carbohydrates_100g (R=0.1164)
  • sugars_100g (R=0.198)

Les autres nutriments ne sont pas corrélés avec le nutrition_grade

Cela correspond aux analyses précédentes et permet d'émettre les mêmes hypothèses

Conclusion¶

Cette analyse permet de mieux comprendre comment est calculé le nutri_score et le nutrition_grade.

Ce sont des indicateurs qui permettent de comparer les produits sur des critères nutritionnels, "A" correspondant à ceux de meilleure qualité nutritionnelle, et "E" au moins favorables.

D'après certaines recommentations, pour rester en bonne santé il convient d'avoir un apport journalier calorique à ne pas dépasser, et de varier les nutriments tout en favorisant les fibres, protéines, fruits et légumes ..., et limiter les produits très caloriques, les acides gras saturés, le sucre, le sel ...

Avec notre analyse on voit que les produits de meilleure qualité et meilleure pour la santé sont ceux à plus faible calorie et étant composés de fibres, ou de protéines. Vient ensuite les produits composés d'un peu de tout les nutriments, ou salés. Et les produits les moins bons sont les produits très sucrées ou très gras avec un très grand apport calorique.

Notre analyse correspond bien aux recommendations faites par l'agence nationale de sécurité sanitaire de l'alimentation, et nous permet de mieux comprendre l'impact des différents nutriments sur l'énergie d'un produit et son nutri_score.